package studyguide.ch19;

import java.io.IOException;

import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Form;
import javax.microedition.lcdui.Gauge;
import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.ImageItem;
import javax.microedition.lcdui.Item;
import javax.microedition.lcdui.ItemCommandListener;
import javax.microedition.lcdui.ItemStateListener;
import javax.microedition.lcdui.StringItem;
import javax.microedition.lcdui.TextField;
import javax.microedition.media.Manager;
import javax.microedition.media.MediaException;
import javax.microedition.media.Player;
import javax.microedition.media.control.FramePositioningControl;
import javax.microedition.media.control.MetaDataControl;
import javax.microedition.media.control.PitchControl;
import javax.microedition.media.control.RateControl;
import javax.microedition.media.control.TempoControl;
import javax.microedition.media.control.VideoControl;

public class MediaDetailsForm extends Form {

	private final MobileMediaMidlet parent;
	private final Command backCommand;
	
	private final StringItem noVideo;
	private final StringItem playButton;
	private final StringItem stopButton;
	private final StringItem status;
	private final StringItem metadata;
	private final TextField ffFrames;
	private final ImageItem snapshot;
	private final Gauge pitchGauge;
	private final Gauge rateGauge;
	private final TextField tempoField;
	
	
	private Player player;
	
	private class MMCommandListener implements CommandListener {
		public void commandAction(Command c, Displayable d) {
			if (c == backCommand) {
				player.close();
				parent.showMainScreen();
			} else {
				throw new RuntimeException("UNKNOWN COMMAND:" + c);
			}
		}
	}
	
	private class PlayerStateListener implements ItemStateListener {

		public void itemStateChanged(Item item) {
			if (item == pitchGauge) {
				PitchControl pitchControl = (PitchControl) player.getControl("PitchControl");
				if (pitchControl == null) {
					// Not supported:
					pitchGauge.setValue(0);
				} else {
					int range = pitchControl.getMaxPitch() - pitchControl.getMinPitch();
					System.out.println("Max pitch    :" + pitchControl.getMaxPitch());
					System.out.println("Min pitch    :" + pitchControl.getMinPitch());
					int step = range / pitchGauge.getMaxValue();
					int input = pitchGauge.getValue() - (pitchGauge.getMaxValue()/2);
					int pitch = step * input;
					System.out.println("Current pitch:" + pitch);
					pitchControl.setPitch(pitch);
				}
			} else if (item == rateGauge) {
				RateControl rateControl = (RateControl) player.getControl("RateControl");
				if (rateControl == null) {
					// Not supported:
					rateGauge.setValue(0);
				} else {
					int range = rateControl.getMaxRate() - rateControl.getMinRate();
					System.out.println("Max rate    :" + rateControl.getMaxRate());
					System.out.println("Min rate    :" + rateControl.getMinRate());
					int step = range / rateGauge.getMaxValue();
					int input = rateGauge.getValue();
					int pitch = step * input + rateControl.getMinRate();
					System.out.println("Current rate:" + pitch);
					rateControl.setRate(pitch);
				}
			} else if (item == tempoField) {
				TempoControl tempoControl = (TempoControl) player.getControl("TempoControl");
				if (tempoControl != null) {
					tempoControl.setTempo(Integer.parseInt(tempoField.getString()));
				}
			}
		}
	}
	
	private class PlayCommandListener implements ItemCommandListener {
		public void commandAction(Command c, Item item) {
			if (item == playButton) {
				if (player.getState() == Player.PREFETCHED) {
					try {
						player.start();
					} catch (MediaException e) {
						status.setText("Error playing:" + e);
					}
				}
			} else if (item == stopButton) {
				try {
					player.stop();
				} catch (MediaException e) {
					status.setText("Error stopping:" + e);
				}
			} else if (item == ffFrames) {
				FramePositioningControl fpControl = (FramePositioningControl) player.getControl("FramePositioningControl");
				if (fpControl != null) {
					fpControl.skip(Integer.parseInt(ffFrames.getString()));
				}
			} else {
				throw new RuntimeException("Unknown item:" + item);
			}
		}
	}
	
	public MediaDetailsForm(MobileMediaMidlet parent) {
		super("Media Details");
		this.parent = parent;
		
		backCommand = new Command("Back", Command.BACK, 1);
		
		PlayCommandListener itemCL = new PlayCommandListener();
		PlayerStateListener stateListener = new PlayerStateListener();
		setItemStateListener(stateListener);
		
		noVideo = new StringItem("", "No video");
		snapshot = new ImageItem("Snapshot:", null, Item.LAYOUT_DEFAULT, "none");
		
		playButton = new StringItem("", "play", StringItem.BUTTON);
		playButton.setDefaultCommand(new Command("play", Command.ITEM, 1));
		playButton.setItemCommandListener(itemCL);
		
		stopButton = new StringItem("", "stop", StringItem.BUTTON);
		stopButton.setDefaultCommand(new Command("stop", Command.ITEM, 1));
		stopButton.setItemCommandListener(itemCL);
		
		status = new StringItem("Status:", "");
		metadata = new StringItem("Info:", "");
		
		ffFrames = new TextField("Frames to skip:", "10", 3, TextField.NUMERIC);
		ffFrames.setDefaultCommand(new Command("skip", Command.ITEM, 1));
		ffFrames.setItemCommandListener(itemCL);
		
		tempoField = new TextField("Tempo:", "", 6, TextField.NUMERIC);
		
		pitchGauge = new Gauge("Pitch:", true, 10, 5);
		rateGauge = new Gauge("Rate:", true, 10, 5);
		
		addCommand(backCommand);
		setCommandListener(new MMCommandListener());
		
		append(noVideo);
		append(playButton);
		append(stopButton);
		append(status);
		append(metadata);
		append(ffFrames);
		append(snapshot);
		append(pitchGauge);
		append(rateGauge);
		append(tempoField);
	}

	public void initialize(final String uri) {
		status.setText("initializing...");
		Thread thread = new Thread(new Runnable() {
			public void run() {
				try { 
					player = Manager.createPlayer(uri);
					player.prefetch();
					status.setText("Ready");
					
					// Load metadata:
					MetaDataControl metaDataControl = (MetaDataControl) player.getControl("MetaDataControl");
					StringBuffer mdBuffer = new StringBuffer();
					if (metaDataControl != null) {
						String[] keys = metaDataControl.getKeys();
						for (int i = 0; i < keys.length; i++) {
							String key = keys[i];
							mdBuffer.append(key);
							mdBuffer.append(" : ");
							mdBuffer.append(metaDataControl.getKeyValue(key));
							mdBuffer.append("\n");
						}
					} else {
						mdBuffer.append("Metadata not available for this file");
					}
					metadata.setText(mdBuffer.toString());
					
					// Load video, if available
					final VideoControl videoControl = (VideoControl) player.getControl("VideoControl");
					if (videoControl != null) {
						Item item = (Item) videoControl.initDisplayMode(VideoControl.USE_GUI_PRIMITIVE, null);
						// Resize the video so that it uses the same width as the screen form
						int width = getWidth();
						double proportion = (double) width / videoControl.getSourceWidth();
						int height = (int) (proportion * videoControl.getSourceHeight());
						videoControl.setDisplaySize(width, height);
						set(0, item);
						
						// Create a "snapshot" command:
						item.setDefaultCommand(new Command("Snapshot", Command.ITEM, 1));
						item.setItemCommandListener(new ItemCommandListener() {
							public void commandAction(Command c, Item item) {
								Thread thread = new Thread( new Runnable() {
									public void run() {
										try {
											byte[] imageData = videoControl.getSnapshot("encoding=png");
											Image image = Image.createImage(imageData, 0, imageData.length);
											snapshot.setImage(image);
										} catch (MediaException e) {
											throw new RuntimeException("ERROR TAKING SNAPSHOT:" + e);
										}
									}
								});
								thread.start();
							}
						});
						
						// Log details about the video:
						System.out.println("Source resolution: " + videoControl.getSourceWidth() 
								+ "x" + videoControl.getSourceHeight());
						System.out.println("Displayed size: " + videoControl.getDisplayWidth() 
								+ "x" + videoControl.getDisplayHeight());
					} else {
						set(0, noVideo);
					}
					
					// Frame positioning is only available for videos:
					FramePositioningControl fpControl = (FramePositioningControl) player.getControl("FramePositioningControl");
					if (fpControl == null) {
						ffFrames.setConstraints(TextField.UNEDITABLE);
					} else {
						ffFrames.setConstraints(TextField.NUMERIC);
					}
					
					snapshot.setImage(null);
					
					// Pitch control:
					PitchControl pitchControl = (PitchControl) player.getControl("PitchControl");
					if (pitchControl == null) {
						pitchGauge.setValue(0);
					} else {
						pitchGauge.setValue(5);
					}
					
					// Rate control
					RateControl rateControl = (RateControl) player.getControl("RateControl");
					if (rateControl == null) {
						rateGauge.setValue(0);
					} else {
						rateGauge.setValue(5);
					}
					
					TempoControl tempoControl = (TempoControl) player.getControl("TempoControl");
					if (tempoControl == null) {
						tempoField.setConstraints(TextField.UNEDITABLE);
						tempoField.setString("N/A");
					} else {
						tempoField.setConstraints(TextField.NUMERIC);
						tempoField.setString(String.valueOf(tempoControl.getTempo()));
					}
				} catch (IOException e) {
					status.setText("Error:" + e);
				} catch (MediaException e) {
					status.setText("Error:" + e);
				}
			}
		});
		thread.start();
	}
	
}
